/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "dal_fastdds/utils/log.hpp"
#include "dal_fastdds/utils/TopicAndTypeHelper.hpp"
#include "dal_fastdds/entity_impl/DalClientImpl.hpp"
#include "dal_fastrtps_cpp/type_support_common.hpp"
#include "dal_fastdds/listener_impl/ClientRespReaderListenerImpl.hpp"

using namespace dal_fastdds;
using namespace eprosima::fastdds::dds;

DalClientImpl::DalClientImpl(std::string service_name,
                             const message_type_support_callbacks_t* req_ts,
                             const message_type_support_callbacks_t* resp_ts)
{
    req_type_name_ = _create_type_name(req_ts);
    resp_type_name_ = _create_type_name(resp_ts);
    req_topic_name_ = std::string(service_name) + "Request";
    resp_topic_name_ = std::string(service_name) + "Reply";
    req_ts_ = req_ts;
    resp_ts_ = resp_ts;
}

DalClientImpl::~DalClientImpl() {}

DomainParticipant* DalClientImpl::GetParticipant()
{
    return f_participant_;
}
void DalClientImpl::SetParticipant(DomainParticipant* participant)
{
    f_participant_ = participant;
}

Publisher* DalClientImpl::GetCSPublisher()
{
    return f_cs_publisher_;
}
void DalClientImpl::SetCSPublisher(Publisher* publisher)
{
    f_cs_publisher_ = publisher;
}

Subscriber* DalClientImpl::GetCSSubscriber()
{
    return f_cs_subscriber_;
}
void DalClientImpl::SetCSSubscriber(Subscriber* subscriber)
{
    f_cs_subscriber_ = subscriber;
}

DataWriter* DalClientImpl::GetReqWriter()
{
    return f_req_writer_;
}
void DalClientImpl::SetReqWriter(DataWriter* req_writer)
{
    f_req_writer_ = req_writer;
}

DataReader* DalClientImpl::GetRespReader()
{
    return f_resp_reader_;
}
void DalClientImpl::SetRespReader(DataReader* resp_reader)
{
    f_resp_reader_ = resp_reader;
}

bool DalClientImpl::GetFastddsReqType(TopicDescription*& topic, TypeSupport& type)
{
    if (!f_participant_) {
        LOG_ERROR_WITH_LOCATION() << "participant is null" << LOG_ENDL;
        return false;
    }

    if (!FindAndCheckFastddsTopicAndType(
            f_participant_, req_topic_name_, req_type_name_, topic, type)) {
        LOG_ERROR_WITH_LOCATION() << "request topic name " << req_topic_name_
                                  << " with incompatible type" << req_type_name_ << LOG_ENDL;
        return false;
    }

    if (!type) {
        auto tsupport = new (std::nothrow) MessageTypeSupport_cpp(req_ts_);
        if (!tsupport) {
            LOG_ERROR_WITH_LOCATION() << "allocate req MessageTypeSupport failed." << LOG_ENDL;
            return false;
        }
        type.reset(tsupport);
    }

    return true;
}

bool DalClientImpl::GetFastddsRespType(TopicDescription*& topic, TypeSupport& type)
{
    if (!f_participant_) {
        LOG_ERROR_WITH_LOCATION() << "participant is null" << LOG_ENDL;
        return false;
    }

    if (!FindAndCheckFastddsTopicAndType(
            f_participant_, resp_topic_name_, resp_type_name_, topic, type)) {
        LOG_ERROR_WITH_LOCATION() << "response topic name " << resp_topic_name_
                                  << " with incompatible type" << resp_type_name_ << LOG_ENDL;
        return false;
    }

    if (!type) {
        auto tsupport = new (std::nothrow) MessageTypeSupport_cpp(resp_ts_);
        if (!tsupport) {
            LOG_ERROR_WITH_LOCATION() << "allocate resp MessageTypeSupport failed." << LOG_ENDL;
            return false;
        }
        type.reset(tsupport);
    }

    return true;
}

bool DalClientImpl::GetFastddsReqTopic(TopicDescription*& topic_desc)
{
    if (!topic_desc) {
        topic_desc =
            f_participant_->create_topic(req_topic_name_, req_type_name_, TOPIC_QOS_DEFAULT);
        if (!topic_desc) {
            LOG_ERROR_WITH_LOCATION() << "create request topic " << req_topic_name_ << " with type "
                                      << req_type_name_ << " failed." << LOG_ENDL;
            return false;
        }
    }
    return true;
}

bool DalClientImpl::GetFastddsRespTopic(TopicDescription*& topic_desc)
{
    if (!topic_desc) {
        topic_desc =
            f_participant_->create_topic(resp_topic_name_, resp_type_name_, TOPIC_QOS_DEFAULT);
        if (!topic_desc) {
            LOG_ERROR_WITH_LOCATION() << "create response topic " << resp_topic_name_
                                      << " with type " << resp_type_name_ << " failed." << LOG_ENDL;
            return false;
        }
    }
    return true;
}

bool DalClientImpl::Clear()
{
    if (f_req_writer_) {
        if (ReturnCode_t::RETCODE_OK != f_cs_publisher_->delete_datawriter(f_req_writer_)) {
            LOG_ERROR_WITH_LOCATION() << "delete request writer failed." << LOG_ENDL;
            return false;
        }
    }
    if (f_resp_reader_) {
        if (ReturnCode_t::RETCODE_OK != f_cs_subscriber_->delete_datareader(f_resp_reader_)) {
            LOG_ERROR_WITH_LOCATION() << "delete response reader failed." << LOG_ENDL;
            return false;
        }
    }

    return true;
}